package ldh.im.fxgui.service;

import ldh.im.ImConfig;
import ldh.im.dto.business.message.MessageObject;
import ldh.im.fxbase.dao.ImMessageDao;
import ldh.im.fxbase.dao.ImMessageSendDao;
import ldh.im.fxbase.data.pojo.*;
import ldh.im.fxbase.data.pojo.status.ImMessageActionStatus;
import ldh.im.fxbase.data.pojo.status.ImMessageStatus;
import ldh.im.fxbase.service.SaveMessageService;
import ldh.im.fxbase.util.*;
import ldh.im.fxgui.util.UiUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 接受服务端推送的业务：
 * 1，消息
 * 2，消息已读动作
 * 3，消息撤回动作
 * 4，数据变更
 * 5，群邀请
 * 6，群退出
 * 7，视频邀请
 * 8，语音邀请
 * 9，聊天禁言（todo)
 * 10，消息屏蔽（todo)
 * 11，消息变更
 * 12，
 */
public class MessageReceiveService {

    private static final Logger LOGGER = LoggerFactory.getLogger(MessageReceiveService.class);

    private ImMessageDao imMessageDao = BeanFactory.getInstance().getBean(ImMessageDao.class);
    private ImMessageSendDao imMessageSendDao = BeanFactory.getInstance().getBean(ImMessageSendDao.class);

    private SaveMessageService saveMessageService = BeanFactory.getInstance().getBean(SaveMessageService.class);
    private MessageRefService messageRefService = BeanFactory.getInstance().getBean(MessageRefService.class);

    /**
     * 接受服务端的消息
     * @param userId
     * @param messageObject
     * @throws SQLException
     */
    public void handleReceiveMessage(String userId, MessageObject messageObject) throws SQLException {
        Set<String> refServerIds = Arrays.asList(messageObject).stream().filter(mo->mo.isRef()).flatMap(mo-> Arrays.stream(mo.getRefMessageIds().split(","))).collect(Collectors.toSet());
        // 处理有引用的消息
        List<MessageObject> refMessages = messageRefService.pullRefMessages(userId, refServerIds.stream().collect(Collectors.toList()));

        List<MessageObject> allMessageObject = new ArrayList<>();
        allMessageObject.add(messageObject);
        allMessageObject.addAll(refMessages);

        List<ImMessage> messages = saveMessageService.saveMessages(userId, allMessageObject, false);
        if (messages.size() > 0) {
            ImMessage imMessage = messages.get(0);
            UiUtil.uiShowMessage(imMessage);
        }
    }

    /**
     * 接受服务器的消息已读
     * @param messageIds
     */
    public void handleReadMessages(String userId, Set<String> messageIds) throws SQLException {
        Set<Long> udpateMessageIdSet = new HashSet();  // 发送者收到已读消息

        List<ImMessageSend> p2gFromUserMessageSendList = new ArrayList<>();  // (群消息)发送者收到已读消息
        List<ImMessage> uiUpdateMessages = new ArrayList<>();
        for (String id : messageIds) {
            if (id.contains(ImConfig.MESSAGE_SPLIT)) {
                String[] keys = id.split(ImConfig.MESSAGE_SPLIT);
                String serverId = keys[0];
                String toUserId = keys[1];
                ImMessage message = imMessageDao.getMessageByServerId(userId, serverId);
                if (message.isSender(userId)) {
                    List<ImMessageSend> messageSends = imMessageSendDao.getByMessageId(message.getId());
                    Optional<ImMessageSend> messageSendOptional = messageSends.stream().filter((ms)->ms.getUserId().equals(toUserId)).findFirst();
                    //imMessageSendDao.getByMessageIdAndToUserId(message.getId(),toUserId);
                    if (messageSendOptional.isPresent()) {
                        ImMessageSend messageSend = messageSendOptional.get();
                        messageSend.setActionStatus(ImMessageActionStatus.readed);
                        messageSend.setUpdateTime(new Date());
                        p2gFromUserMessageSendList.add(messageSend);
                    }
                    Long readedSize = messageSends.stream().filter((ms)->ms.getActionStatus() == ImMessageActionStatus.readed).count();
                    if (readedSize.intValue() == messageSends.size()) {
                        message.setStatus(ImMessageStatus.readed);
                        message.setActionStatus(ImMessageActionStatus.readed);
                        message.setUpdateDateTime(new Date());
                        imMessageDao.updateMessageStatus(message.getId(), ImMessageStatus.readed, ImMessageActionStatus.readed);
                        uiUpdateMessages.add(message);
                    }
                } else {
                    udpateMessageIdSet.add(message.getId());
                }
            } else {
                ImMessage message = imMessageDao.getMessageByServerId(userId, id);
                uiUpdateMessages.add(message);
                if (message.isSender(userId)) {
                    udpateMessageIdSet.add(message.getId());
                    message.setActionStatus(ImMessageActionStatus.readed);
                } else {
//                    udpateMessageIdSet.add(message.getId());
                    message.setUpdateDateTime(new Date());
                    message.setStatus(ImMessageStatus.readed);
                    message.setActionStatus(ImMessageActionStatus.readed);
                    imMessageDao.updateMessageStatus(message.getId(), ImMessageStatus.readed, ImMessageActionStatus.readed);
                }
            }
        }
        imMessageDao.changeMessageActionStatus(udpateMessageIdSet, ImMessageActionStatus.readed);
        imMessageSendDao.batchUpdates(p2gFromUserMessageSendList);

        FxThreadUtil.runLater(()->{
            for (ImMessage message : uiUpdateMessages) {
                UiUtil.uiUpdateMessage(message);
            }
        });
    }

    /**
     * 接受服务器的消息回撤
     * @param messageIds
     */
    public void handleWithdrawMessages(String userId, Set<String> messageIds) throws SQLException {
        List<ImMessage> uiUpdateMessages = new ArrayList<>(messageIds.size());
        for (String id : messageIds) {
            ImMessage message = imMessageDao.getMessageByServerId(userId, id);
            uiUpdateMessages.add(message);
            imMessageDao.updateMessageStatus(message.getId(), ImMessageStatus.withdrawed, ImMessageActionStatus.withdrawed);
        }

        FxThreadUtil.runLater(()->{
            for (ImMessage message : uiUpdateMessages) {
                UiUtil.uiUpdateMessage(message);
            }
        });
    }
}
